home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / (A)TB / (A)TBY.ADF / Soundzap / SoundZAP.c < prev    next >
C/C++ Source or Header  |  1992-03-19  |  14KB  |  539 lines

  1. /************************/
  2. /**SoundZAP Version 2.4**/
  3. /************************/
  4.  
  5. /*
  6.  *  This program was compiled with Matthew Dillon's DICE C compiler, which
  7.  *  automatically opens and closes the Amiga libraries as they are needed.
  8.  *  If your compiler does not do this you will have to Add the appropriate
  9.  *  code (or get DICE!!).
  10.  */
  11.  
  12.  
  13. #include <exec/types.h>
  14. #include <exec/memory.h>
  15. #include <libraries/dos.h>
  16. #include <stdio.h>
  17. #include <iff/iff.h>
  18. #include <iff/8svx.h>
  19. #include "SoundZAP.h"
  20.  
  21.  
  22. void main(int argc, char *argv[])
  23. {
  24.     char comline[33];
  25.     struct options *Opt;
  26.  
  27.  
  28.     if (argc<2) GiveUsage();
  29.  
  30.     if ((Opt=(UBYTE *)AllocMem(sizeof(struct options),MEMF_PUBLIC))==NULL)
  31.         CleanUp(Opt,5);
  32.  
  33.     Opt->BuffSize  = DEFAULT_SIZE;
  34.     Opt->FlipSign  = FALSE;
  35.     Opt->KillChunk = FALSE;
  36.     Opt->SampRate  = DEFAULT_RATE;
  37.     Opt->IFFOut    = TRUE;
  38.     Opt->InType    = UNKNOWN;
  39.     Opt->MuLaw     = FALSE;
  40.     Opt->SampChk   = TRUE;
  41.     Opt->Data      = NULL;
  42.     Opt->Size      = 0;
  43.     Opt->Bits      = 8;
  44.     strcpy(Opt->inname,"");
  45.     strcpy(Opt->outname,"");
  46.  
  47.     while (--argc > 0)
  48.     {
  49.         strcpy(comline,argv[argc]);
  50.         if (comline[0]=='-')
  51.             ProcessOpt(Opt,comline);
  52.         else
  53.         {
  54.            strcpy(Opt->outname,Opt->inname);
  55.            strcpy(Opt->inname,comline);
  56.         }
  57.     }
  58.     if (strlen(Opt->inname)==0)
  59.         GiveUsage();
  60.  
  61.     if (strlen(Opt->outname)==0)
  62.     {
  63.         int l;
  64.  
  65.         strcpy(Opt->outname,Opt->inname);
  66.         l=strlen(Opt->outname);
  67.         if(Opt->outname[l-4]=='.')
  68.             Opt->outname[l-4]='\0';
  69.         if(Opt->outname[l-3]=='.')
  70.             Opt->outname[l-3]='\0';
  71.         strcat(Opt->outname,".iff");
  72.     }
  73.     printf("Input File: %s\nOutput File: %s\n",Opt->inname,Opt->outname);
  74.     if (Opt->BuffSize!=0) printf("Buffer Size: %d bytes\n",Opt->BuffSize);
  75.     else printf("Allocating maximum buffer size.\n");
  76.     if(!Opt->SampChk)
  77.         printf("Sample Rate: %d samples per second\n",Opt->SampRate);
  78.     AnalyzeData(Opt);
  79.     CleanUp(Opt,0);
  80. }
  81.  
  82.  
  83. void GiveUsage()
  84. {
  85.     printf("SoundZap v2.4\n");
  86.     printf("Usage:  SoundZAP [<options>] SOURCE [DESTINATION]\n");
  87.     printf("    (actually, the options can appear anywhere)\n\n");
  88.     printf("    options:    -w         Output RAW data\n");
  89.     printf("                -s         Toggle signed/unsigned output\n");
  90.     printf("                -n         Don't create extra chunks in IFF output\n");
  91.     printf("                -f         Assume input data is RAW\n");
  92.     printf("                -b<n>      Use a buffer size of n kilobytes\n");
  93.     printf("                            if n==0 then SoundZAP will try to\n");
  94.     printf("                            allocate enough memory to convert\n");
  95.     printf("                            the whole sample in one shot.\n");
  96.     printf("                -r<n>      Change sample rate.\n");
  97.     printf("                            where n is the sample rate or\n");
  98.     printf("                            one of the built in values.\n");
  99.     printf("\nSee documentation for more info.\n");
  100.     printf("mrc113@psuvm.psu.edu\n");
  101.     exit(0);
  102. }
  103.  
  104. void ProcessOpt(struct options *Opt, char com[])
  105. {
  106.     int len;
  107.     ULONG n;
  108.  
  109.     switch (com[1])
  110.     {
  111.         case 'w' :  Opt->IFFOut=FALSE;
  112.                     break;
  113.  
  114.         case 's' :  Opt->FlipSign=TRUE;
  115.                     break;
  116.  
  117.         case 'n' :  Opt->KillChunk=TRUE;
  118.                     break;
  119.  
  120.         case 'f' :  Opt->InType=RAW;
  121.                     break;
  122.  
  123.         case 'b' :  len=strlen(com)-2;
  124.                     if (len==0)
  125.                         CleanUp(Opt,2);
  126.                     Opt->BuffSize=(ULONG)atoi(com+2)*1024;
  127.                     break;
  128.  
  129.         case 'r' :  len=strlen(com)-2;
  130.                     if (len==0)
  131.                         CleanUp(Opt,3);
  132.                     if (len==1)
  133.                     {
  134.                         switch (com[2])
  135.                         {
  136.                             case '5' :  Opt->SampRate=5696;
  137.                                         break;
  138.  
  139.                             case '7' :  Opt->SampRate=7596;
  140.                                         break;
  141.  
  142.                             case '8' :  Opt->SampRate=8000;
  143.                                         break;
  144.  
  145.                             case '2' :  Opt->SampRate=22790;
  146.                                         break;
  147.  
  148.                             default  :  Opt->SampRate=11395;
  149.                         }
  150.                     }
  151.                     else
  152.                     {
  153.                         n=(LONG)atoi(com+2);
  154.                         if (n!=0) Opt->SampRate=n;
  155.                         else Opt->SampRate=11395;
  156.                     }
  157.                     Opt->SampChk=FALSE;
  158.                     break;
  159.  
  160.  
  161.         default  :  CleanUp(Opt,4);
  162.     }
  163. }
  164.  
  165. void CleanUp(struct options *Opt, int Error)
  166. {
  167.     if (Opt->Data) FreeMem(Opt->Data,Opt->BuffSize);
  168.     if (Opt) FreeMem(Opt,sizeof(struct options));
  169.     if (in)   Close(in);
  170.     if (out)  Close(out);
  171.     if (Error==0) exit(0);
  172.     else
  173.     {
  174.         printf("%s",ErrorMessages[Error]);
  175.         exit(20);
  176.     }
  177. }
  178.  
  179. void AnalyzeData(struct options *Opt)
  180. {
  181.     ULONG MagicWord;
  182.     char IsMac[8];
  183.  
  184.     if ((in=(struct FileHandle *)Open(Opt->inname,MODE_OLDFILE))==NULL)
  185.         CleanUp(Opt,6);
  186.  
  187.     if(Opt->BuffSize==0)
  188.     {
  189.         Seek(in,0,OFFSET_END);
  190.         Opt->BuffSize=Seek(in,0,OFFSET_BEGINNING);
  191.     }
  192.  
  193.     if ((Opt->Data=(UBYTE *)AllocMem(Opt->BuffSize,MEMF_PUBLIC))==NULL)
  194.         CleanUp(Opt,5);
  195.  
  196.     Read(in,&MagicWord,4);
  197.     if (Opt->InType==UNKNOWN)
  198.     {
  199.         if (MagicWord==0x2e736e64)                /* '.snd' */
  200.             ConvertAU(Opt);
  201.         else if (MagicWord==0x464f524d)           /* 'FORM' */
  202.             ConvertIFF(Opt);
  203.         else if (MagicWord==0x43726561)           /* 'Crea' */
  204.             ConvertVOC(Opt);
  205.         else if (MagicWord==0x52494646)           /* 'RIFF' */
  206.             ConvertWAV(Opt);
  207.     }
  208.     Seek(in,65,OFFSET_BEGINNING);
  209.     Read(in,IsMac,8);
  210.     if (!strcmp(IsMac,"FSSDSFX!"))
  211.         ConvertMAC(Opt);
  212.     GuidoCheck(Opt);
  213. }
  214.  
  215. /*  This routine is a modified version of Guido van Rossum's (guido@cwi.nl)
  216.  *  'whatsound' routine. It guesses the sound file type (signed/unsigned/mu-law)
  217.  *  by checking how the values in the file are distributed. Thanks Guido!!
  218.  */
  219.  
  220. void GuidoCheck(struct options *Opt)
  221. {
  222.     LONG a,n,sum;
  223.     unsigned long bin[4];
  224.     int x;
  225.     BPTR op=Output();
  226.  
  227.     if(Opt->FlipSign)
  228.     {
  229.         Seek(in,0,OFFSET_END);
  230.         Opt->Size=Seek(in,0,OFFSET_BEGINNING);
  231.         ConvertRaw(Opt);
  232.     }
  233.  
  234.     printf("Input is RAW data file.\n");
  235.     for (a=0; a<4; a++)
  236.         bin[a]=0;
  237.     do
  238.     {
  239.         n=Read(in,Opt->Data,Opt->BuffSize);
  240.         for(a=0; a<n; a++)
  241.             bin[Opt->Data[a]/64]++;
  242.     }
  243.     while (n==Opt->BuffSize);
  244.     if(bin[2]==0 && bin[3]==0)
  245.         CleanUp(Opt,7);
  246.  
  247.     x=((bin[0]+bin[3])*100)/(bin[1]+bin[2]);
  248.     if(x>=300)
  249.         Opt->FlipSign=FALSE;
  250.     else if ( x <= 33)
  251.         Opt->FlipSign=TRUE;
  252.     else if ( (x >= 50) && (x <= 200))
  253.         Opt->MuLaw=TRUE;
  254.     printf("Done.\n");
  255.     if(Opt->SampChk && Opt->MuLaw) Opt->SampRate=8000;
  256.     Seek(in,0,OFFSET_END);
  257.     Opt->Size=Seek(in,0,OFFSET_BEGINNING);
  258.     ConvertRaw(Opt);
  259. }
  260.  
  261.  
  262. void ConvertRaw(struct options *Opt)
  263. {
  264.     LONG b_read,i,scale,b_written,total;
  265.     int max;
  266.     signed char logs[256];
  267.     BPTR op=Output();
  268.  
  269.  
  270.     if((out=(struct FileHandle *)Open(Opt->outname,MODE_NEWFILE))==NULL)
  271.         CleanUp(Opt,8);
  272.  
  273.     if (Opt->IFFOut)
  274.         WriteIFFStuff(Opt);
  275.  
  276.     if (Opt->MuLaw)
  277.     {
  278.         Write(op,"Building log tables...",22);
  279.         max=getscale(Opt);
  280.         maketable(logs,max);
  281.         printf("Done.\n");
  282.         if (Opt->InType==AU)
  283.             Seek(in,32,OFFSET_BEGINNING);
  284.         else
  285.             Seek(in,0,OFFSET_BEGINNING);
  286.     }
  287.     scale=Opt->Bits/8;
  288.     total=0;
  289.     do
  290.     {
  291.         b_read=Read(in,Opt->Data,Opt->BuffSize)/scale;
  292.  
  293.         if(Opt->FlipSign)
  294.             for (i=0; i<b_read; i++)
  295.                 Opt->Data[i] ^= 0x80;
  296.         else if(Opt->MuLaw)
  297.             for (i=0; i<b_read; i++)
  298.                 Opt->Data[i]=logs[Opt->Data[i]];
  299.         else if(scale!=1)
  300.             for (i=0; i<b_read; i++)
  301.                 Opt->Data[i]=Opt->Data[i*scale];
  302.  
  303.         total+=b_read;
  304.         if (total > Opt->Size)
  305.             b_read-=total-Opt->Size;
  306.         b_written=Write(out,Opt->Data,b_read);
  307.         if(b_written!=b_read) CleanUp(Opt,10);
  308.     }
  309.     while(total < Opt->Size);
  310.  
  311.     if(Opt->IFFOut)
  312.         Write(out,"\0\0\0",(4-total%4)&3);
  313.     CleanUp(Opt,0);
  314. }
  315.  
  316. void WriteIFFStuff(struct options *Opt)
  317. {
  318.     int i,s;
  319.     ChunkHeader Form, V8Hdr, Body, Auth, Anno;
  320.  
  321.     printf("Output file is in IFF 8SVX format.\n");
  322.     Voice8Header V8H = {0,0,32,8363,1,0,Unity};
  323.  
  324.     if (Opt->KillChunk)
  325.         s=0;
  326.     else s=68;
  327.  
  328.     Form.ckID = FORM;
  329.     Form.ckSize = 40 + s + Opt->Size + ((4-(Opt->Size%4))&3);
  330.  
  331.     Write(out,&Form,8);
  332.  
  333.     i=ID_8SVX;
  334.     Write(out,&i,4);
  335.  
  336.     if (!Opt->KillChunk)
  337.     {
  338.         Auth.ckID  = ID_AUTH;
  339.         Auth.ckSize = 16;
  340.         Write(out,&Auth,8);
  341.         Write(out,Author,16);
  342.  
  343.         Anno.ckID = ID_ANNO;
  344.         Anno.ckSize = 36;
  345.         Write(out,&Anno,8);
  346.         Write(out,Annotation,36);
  347.     }
  348.  
  349.     V8Hdr.ckID = ID_VHDR;
  350.     V8Hdr.ckSize = 20;
  351.     Write(out,&V8Hdr,8);
  352.  
  353.     V8H.oneShotHiSamples = Opt->Size;
  354.     V8H.samplesPerSec = Opt->SampRate;
  355.     Write(out,&V8H,20);
  356.  
  357.     Body.ckID = ID_BODY;
  358.     Body.ckSize = Opt->Size + ((4-(Opt->Size%4))&3);
  359.     Write(out,&Body,8);
  360. }
  361.  
  362.  
  363. void ConvertVOC(struct options *Opt)
  364. {
  365.     UBYTE c[2];
  366.  
  367.     printf("Input is .VOC file\n");
  368.     if(Opt->SampChk)
  369.     {
  370.         Seek(in,30,OFFSET_BEGINNING);
  371.         Read(in,c,2);
  372.         if(c[1]!=0)
  373.             CleanUp(Opt,9);
  374.         Opt->SampRate=1000000/(256-c[0]);
  375.     }
  376.     Opt->FlipSign=TRUE;
  377.     Seek(in,0,OFFSET_END);
  378.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
  379.     Seek(in,32,OFFSET_BEGINNING);
  380.     ConvertRaw(Opt);
  381. }
  382.  
  383. void ConvertWAV(struct options *Opt)
  384. {
  385.     printf("Input is .WAV file\n");
  386.     Opt->FlipSign=TRUE;
  387.     Seek(in,0,OFFSET_END);
  388.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-44;
  389.     Seek(in,44,OFFSET_BEGINNING);
  390.     ConvertRaw(Opt);
  391. }
  392.  
  393. void ConvertMAC(struct options *Opt)
  394. {
  395.     printf("Input is Macintosh sound file\n");
  396.     Opt->FlipSign=TRUE;
  397.     Seek(in,0,OFFSET_END);
  398.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-668;
  399.     Seek(in,128,OFFSET_BEGINNING);
  400.     ConvertRaw(Opt);
  401. }
  402.  
  403. /* Thanks to Sean Connolly for sending me info on the .au sound format.*/
  404.  
  405. void ConvertAU(struct options *Opt)
  406. {
  407.     ULONG i;
  408.     int q;
  409.     AUHeader AUHdr;
  410.  
  411.     Seek(in,0,OFFSET_END);
  412.     Opt->Size=Seek(in,0,OFFSET_BEGINNING)-32;
  413.     Read(in,&AUHdr,sizeof(AUHdr));
  414.     switch (AUHdr.encoding)
  415.     {
  416.         case 1   :  Opt->MuLaw=TRUE;
  417.                     printf("Input is 16-bit u-lawed .au file.\n");
  418.                     break;
  419.  
  420.         case 2   :  Opt->Bits=8;
  421.                     printf("Input is 8-bit linear .au file.\n");
  422.                     break;
  423.  
  424.         case 3   :  Opt->Bits=16;
  425.                     Opt->Size/=2;
  426.                     printf("Input is 16-bit linear .au file.\n");
  427.                     break;
  428.  
  429.         case 4   :  Opt->Bits=24;
  430.                     Opt->Size/=3;
  431.                     printf("Input is 24-bit linear .au file.\n");
  432.                     break;
  433.  
  434.         case 5   :  Opt->Bits=32;
  435.                     Opt->Size/=4;
  436.                     printf("Input is 32-bit linear .au file.\n");
  437.                     break;
  438.  
  439.         default  :  CleanUp(Opt,9);
  440.                     break;
  441.     }
  442.  
  443.     if (Opt->SampChk)
  444.         Opt->SampRate=AUHdr.sample_rate;
  445.     ConvertRaw(Opt);
  446. }
  447.  
  448. void ConvertIFF(struct options *Opt)
  449. {
  450.     ULONG ThisID,ChunkSize,tmp;
  451.     LONG size,bytes;
  452.     Voice8Header V8H;
  453.  
  454.     printf("Input file is in IFF 8SVX format.\n");
  455.     Seek(in,0,OFFSET_END);
  456.     if((size=Seek(in,0,OFFSET_BEGINNING)) > 50)
  457.     {
  458.         Read(in,&ThisID,4);
  459.         Read(in,&tmp,4);
  460.         if((tmp+8) == size)
  461.         {
  462.             do bytes=Read(in,&ThisID,4);
  463.             while ((bytes==4) && (ThisID!=ID_VHDR));
  464.             if(bytes==4)
  465.             {
  466.                 Read(in,&tmp,4);
  467.                 Read(in,&V8H,20);
  468.                 if (Opt->SampChk)
  469.                     Opt->SampRate=V8H.samplesPerSec;
  470.                 do bytes=Read(in,&ThisID,4);
  471.                 while ((bytes==4) && (ThisID!=ID_BODY));
  472.                 if(bytes==4)
  473.                 {
  474.                     Read(in,&Opt->Size,4);
  475.                     ConvertRaw(Opt);
  476.                 }
  477.             }
  478.         }
  479.     }
  480.     CleanUp(Opt,11);
  481. }
  482.  
  483.  
  484. /*--------------------------------------------------------------------------*
  485.  * The following routine was extracted from posting by Brian Foley.         *
  486.  * Brian Foley          email: bfoley@greatlakes.Central.Sun.COM            *
  487.  * Systems Engineer     smail:  1000 Town Center                            *
  488.  * Sun Microsystems             Suite 1700                                  *
  489.  * GreatLakes Region            Southfield, MI 48075   (313) 352-7070       *
  490.  *--------------------------------------------------------------------------*/
  491.  
  492. int ulaw2linear(unsigned char ulawbyte)
  493. {
  494.         static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
  495.                int sign, exponent, mantissa, sample;
  496.  
  497.         ulawbyte    = ~ulawbyte;
  498.         sign        =  ulawbyte & 0x80;
  499.         exponent    = (ulawbyte >> 4) & 0x07;
  500.         mantissa    =  ulawbyte & 0x0F;
  501.         sample      = (exp_lut[exponent] + (mantissa << (exponent + 3)));
  502.         if ( sign ) sample = -sample;
  503.         return sample;
  504. }
  505. int getscale(struct options *Opt)
  506. {
  507.         int count, max = 0, i;
  508.  
  509.         do
  510.         {
  511.             count    = Read(in, Opt->Data, Opt->BuffSize);
  512.             for ( i = 0; i < count; i++ )
  513.                 max     = MAX(abs(ulaw2linear(Opt->Data[i])), max);
  514.         }
  515.         while ( count == Opt->BuffSize );
  516.  
  517.         return max;
  518. }
  519.  
  520. void maketable(signed char *logs, int max)
  521. {
  522.         int i, c, d;
  523.  
  524.         for ( i = 0; i < 256; i++ )
  525.         {
  526.                 c = ( ulaw2linear(i) * ulaw2linear(0) ) / max;
  527.                 d = abs(c) & 0xFF;
  528.                 if ( d > 0x7F )
  529.                     if ( c > 0 )
  530.                         logs[i] = (signed char) ( c / 256 + 1 );
  531.                     else
  532.                         logs[i] = (signed char) ( c / 256 - 1 );
  533.                 else
  534.                     logs[i] = (signed char) ( c / 256 );
  535.         }
  536. }
  537.  
  538.  
  539.